/*
Copyright 2009 - 2013 Peter Krajnc, SCREENWORKER

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/
package org.compactmvc.services.async.rest
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	
	import org.compactmvc.interfaces.IModel;
	import org.compactmvc.patterns.Controller;
	import org.compactmvc.patterns.Model;
	import org.compactmvc.services.interfaces.IRESTfulService;
	import org.compactmvc.services.vo.RestServiceItemVO;
	
	public class RESTfulService extends Model implements IModel, IRESTfulService
	{
		public static var NAME:String = 'RESTfulService';

		protected var _queueMap:Vector.<RestServiceItemVO>;
		protected var _requestSequence:Number = 0;
		protected var _dataLoader:URLLoader;
		protected var _currentItem:RestServiceItemVO;		
		protected var _uri:String;

		public function RESTfulService(name:String, controller:Controller)
		{
			super(name, controller);
			
			_queueMap = new Vector.<RestServiceItemVO>();
			
			_dataLoader = new URLLoader();
			_dataLoader.addEventListener(ProgressEvent.PROGRESS, loaderProgressHandler, false, 0, true);
			_dataLoader.addEventListener(IOErrorEvent.IO_ERROR, loaderIOErrorHandler, false, 0, true);
			_dataLoader.addEventListener(Event.COMPLETE, loaderCompleteHandler, false, 0, true);
			_dataLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loaderSecurityErrorHandler, false, 0, true);
		}
		
		public function dispose():void
		{		
			_dataLoader.close();
			_dataLoader.removeEventListener(ProgressEvent.PROGRESS, loaderProgressHandler );
			_dataLoader.removeEventListener(IOErrorEvent.IO_ERROR, loaderIOErrorHandler);
			_dataLoader.removeEventListener(Event.COMPLETE, loaderCompleteHandler);
			_dataLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, loaderSecurityErrorHandler);	
			_dataLoader = null;
		}
		
		override public function removeHandler():void
		{
			dispose();
		}
		
		/**
		 * loads a xml file from the given url
		 * @param url
		 * 
		 */		
		protected function load(request:URLRequest, name:String=null, resultHandler:Function=null, faultHandler:Function=null, mockupFilePath:String=null):void 
		{
			var vo:RestServiceItemVO = new RestServiceItemVO();
			vo.request = request;
			vo.name = name;
			vo.resultHandler = resultHandler;
			vo.faultHandler = faultHandler;
			vo.mockupFilePath = mockupFilePath;
			
			addToQueue(vo);
			
		}
		
		/**
		 * adds a new item to the  queue list
		 * @param item
		 * 
		 */		
		private function addToQueue(item:RestServiceItemVO):void
		{
			_queueMap.push(item);
			
			if(!_currentItem)
				nextItem();	
		}
		
		/**
		 * remove a queue item and close loading operation
		 * @param itemToRemove
		 * @return 
		 * 
		 */		
		public function removeFromQueue(itemToRemove:RestServiceItemVO):RestServiceItemVO
		{
			//remove from queue list
			for (var i:int = 0; i < _queueMap.length; i++)
			{
				var item:RestServiceItemVO = _queueMap[i];
				if(item == itemToRemove)
				{
					_queueMap.splice(i, 1);			
					break;
				}	
			}	
			
			//if item is current, stop loading
			if(_currentItem == itemToRemove)
			{
				_dataLoader.close();
				_currentItem = null;
				nextItem();
				return itemToRemove;
			}
			
			return itemToRemove;			
		}
		
		/**
		 * starts loading the next queue items xml file 
		 * 
		 */		
		private function nextItem():void
		{
			_currentItem = null;
			
			if(_queueMap.length == 0)
				return;
			
			_currentItem = _queueMap.shift();
			
			//mockup?
			if(_currentItem.mockupFilePath)
			{
				_currentItem.request = new URLRequest(_currentItem.mockupFilePath);
			}
			
			try 
			{	
				_dataLoader.load(_currentItem.request);	
			} 
			catch (error:Error) 
			{
				var msg:String = 'Unable to load requested document:' + error.message;
				
				if(_currentItem.faultHandler != null)
					_currentItem.faultHandler(msg);
				
				errorHandler(msg);
				
				nextItem();				
			}		
		}
		
		private function loaderProgressHandler( e:ProgressEvent ):void
		{
			progressHandler(e.bytesLoaded/e.bytesTotal);
		}
		
		private function loaderIOErrorHandler(e:IOErrorEvent):void 
		{
			IOErrorHandler(e.text);
			
			nextItem();
		}
		
		private function loaderSecurityErrorHandler(e:SecurityErrorEvent):void
		{
			securityErrorHandler(e.text);
			
			nextItem();
		}
		
		private function loaderCompleteHandler(e:Event):void 
		{		
			if(e.target.data)
			{
				_currentItem.data = e.target.data;
				
				if(_currentItem.resultHandler != null)
					_currentItem.resultHandler(_currentItem);
				
				completeHandler(_currentItem);		
			}			
			else
			{
				var msg:String = 'Object is not valid!';
				
				if(_currentItem.faultHandler != null)
					_currentItem.faultHandler(msg);
				
				errorHandler(msg);
			}
			nextItem();
		}
		
		public function progressHandler(progress:Number):void
		{
			//overriden by subclass
		}
		
		public function IOErrorHandler(message:String):void 
		{
			//overriden by subclass
		}
		
		public function errorHandler(message:String):void 
		{
			//overriden by subclass
		}
		
		public function completeHandler(result:RestServiceItemVO):void 
		{
			//overriden by subclass
		}
		
		public function securityErrorHandler(message:String):void
		{
			//overriden by subclass
		}
		
		public function get uri():String
		{
			return _uri;
		}

		public function set uri(value:String):void
		{
			_uri = value;
		}


	}
}